package com.xqboss.apps.service.order.type.impl;

import com.xqboss.apps.constant.Config;
import com.xqboss.apps.constant.RedisKey;
import com.xqboss.apps.domain.market.Market;
import com.xqboss.apps.domain.order.OrderItem;
import com.xqboss.apps.domain.order.OrderMain;
import com.xqboss.apps.dto.order.CreateOrderDto;
import com.xqboss.apps.dto.order.WebOrderListDto;
import com.xqboss.apps.enums.market.MarketStatusEnum;
import com.xqboss.apps.enums.market.MarketTypeEnum;
import com.xqboss.apps.enums.mq.AppMqNormalEnum;
import com.xqboss.apps.enums.order.OrderTypeEnum;
import com.xqboss.apps.enums.order.OutOrderStatusEnum;
import com.xqboss.apps.enums.user.UserWalletEnum;
import com.xqboss.apps.enums.user.WalletChangeDirectionEnum;
import com.xqboss.apps.enums.user.WalletChangeTypeEnum;
import com.xqboss.apps.enums.user.WalletWrenchChangeTypeEnum;
import com.xqboss.apps.service.box.BoxService;
import com.xqboss.apps.service.market.MarketService;
import com.xqboss.apps.service.nft.NftService;
import com.xqboss.apps.service.order.OrderItemService;
import com.xqboss.apps.service.order.OrderService;
import com.xqboss.apps.service.order.type.OrderTypeExecutor;
import com.xqboss.apps.service.user.SysUserNftService;
import com.xqboss.apps.service.user.SysUserWalletService;
import com.xqboss.apps.service.user.UserAssetWrenchRecordService;
import com.xqboss.apps.service.user.UserBoxService;
import com.xqboss.common.core.domain.entity.SysUser;
import com.xqboss.common.core.mq.MqSender;
import com.xqboss.common.core.redis.RedisCache;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.SecurityUtils;
import com.xqboss.system.service.ISysConfigService;
import com.xqboss.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 市场订单执行器
 */
@Slf4j
@Component(value = OrderTypeEnum.Code.Market)
public class MarketOrderTypeExecutor extends OrderTypeExecutor {

    @Autowired
    private ISysConfigService sysConfigService;
    @Autowired
    private MarketService marketService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private UserBoxService userBoxService;
    @Autowired
    private SysUserNftService userNftService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private ISysUserService userService;

    @Lazy
    @Autowired
    private OrderService orderService;

    @Lazy
    @Autowired
    private SysUserWalletService userWalletService;

    @Lazy
    @Autowired
    private NftService nftService;

    @Lazy
    @Autowired
    private BoxService boxService;

    @Autowired
    private MqSender mqSender;
    @Autowired
    private UserAssetWrenchRecordService userAssetWrenchRecordService;


    @Override
    protected OrderMain preValidate(CreateOrderDto params) {
        // 1. 获取市场信息
        Market marketInfo = marketService.getMarketInfo(params.getSourceId());
        // 判断是否已经有同类未支付订单商品，如果有则返回订单信息，
        WebOrderListDto queryWaitPayOrder = new WebOrderListDto();
        queryWaitPayOrder.setOrderType(OrderTypeEnum.Market);
        queryWaitPayOrder.setOrderStatus(OutOrderStatusEnum.UN_PAY);
        queryWaitPayOrder.setMarketType(marketInfo.getType());
        queryWaitPayOrder.setPageNum(1);
        queryWaitPayOrder.setPageSize(1);
        queryWaitPayOrder.setOrderByColumn("id");
        queryWaitPayOrder.setSortAsc(false);
        queryWaitPayOrder.setBuyerId(SecurityUtils.getUserId());
        List<OrderMain> orderList = orderService.getOrderList(queryWaitPayOrder);
        if(!orderList.isEmpty()){
            throw new ServiceException("存在待支付订单！");
        }

        if(Objects.isNull(marketInfo)){
            throw new ServiceException("转卖不存在!");
        }
        // 2. 退市判断
        switch (marketInfo.getType()){
            case NORMAL:
            case EQUIPMENT:
                if(!nftService.isBoxResell(marketInfo.getNftId())){
                    throw new ServiceException("已退市，暂时无法购买");
                }
                break;
            case BOX:
                if(!boxService.isBoxResell(marketInfo.getBoxId())){
                    throw new ServiceException("已退市，暂时无法购买");
                }
                break;
            case MATERIAL:
                if(Objects.equals(marketInfo.getSourceId(), UserWalletEnum.INTEGRAL.getValue().longValue())){
                    // 判断热豆是否开启转卖
                    if(!sysConfigService.getValue(Config.Sys.Treasury.转卖开关)){
                        throw new ServiceException("已退市，暂时无法购买");
                    }
                }else if (Objects.equals(marketInfo.getSourceId(), UserWalletEnum.WRENCH.getValue().longValue())){
                    // 判断扳手是否开启转卖
                    if(!sysConfigService.getValue(Config.Sys.Treasury.扳手转卖开关)){
                        throw new ServiceException("扳手已退市，暂时无法购买");
                    }
                }else {
                    throw new ServiceException("不支持的转卖");
                }
                break;
            default:
                throw new ServiceException("不支持的转卖");
        }
        if(Objects.equals(marketInfo.getUserId(), SecurityUtils.getUserId())){
            throw new ServiceException("不能购买自己转卖的商品！");
        }
        if(marketInfo.getStatus() != MarketStatusEnum.TRADING){
            // 未上架
            if(marketInfo.getStatus() == MarketStatusEnum.CANCEL){
                throw new ServiceException("商品已下架！");
            }else if(marketInfo.getStatus() == MarketStatusEnum.SOLD_OUT){
                throw new ServiceException("来慢了，被别人带走了~");
            }
        }
        if(marketInfo.getStock() < params.getQuantity()){
            if(marketInfo.getType() == MarketTypeEnum.NORMAL || marketInfo.getType() == MarketTypeEnum.EQUIPMENT){
                if(marketInfo.getLockStock() <= 0){
                    throw new ServiceException("来慢了，被别人带走了~");
                }else{
                    throw new ServiceException("来慢了，被别人下单了~");
                }
            }else{
                throw new ServiceException("库存不足，当前剩余：" + marketInfo.getStock());
            }
        }

        // 3. 判断订单金额是否正常
        BigDecimal orderPrice = marketInfo.getPrice().multiply(new BigDecimal(String.valueOf(params.getQuantity())));
        if(params.getPrice().compareTo(orderPrice) != 0){
            // 金额不一致
            throw new ServiceException("商品价格已修改，请刷新重试！");
        }

        // 计算交易手续费
        BigDecimal txFee = orderPrice.multiply(sysConfigService.getValue(Config.Sys.Market.交易费率)).setScale(2, RoundingMode.DOWN);
        txFee = txFee.max(sysConfigService.getValue(Config.Sys.Market.最低交易费));


        OrderMain order = buildOrder(params);
        order.setSellerUserId(marketInfo.getUserId());
        SysUser user = userService.selectUserById(marketInfo.getUserId());
        if(user != null){
            order.setSellerNick(user.getNickName());
        }
        order.setMarketType(marketInfo.getType());
        order.setPaymentAmount(orderPrice);
        order.setTransactionFee(txFee);
        order.setTotalAmount(orderPrice);

        order.setAutoCancelTime(LocalDateTime.now().plusMinutes(sysConfigService.getValue(Config.Sys.Order.订单超时时间)));

        OrderItem orderItem = buildOrderItem(order, params);
        orderItem.setMarketType(marketInfo.getType());
        order.setOrderItems(Collections.singletonList(orderItem));
        orderItem.setSpuId(marketInfo.getId());
        orderItem.setSpuName(marketInfo.getTitle());
        orderItem.setSkuImg(marketInfo.getImg());
        orderItem.setSkuPrice(marketInfo.getPrice());
//        orderItem.setPublishName(marketInfo.getPublishName());
        orderItem.setSkuId(marketInfo.getNftNumberId());
        orderItem.setSkuSpec(marketInfo.getNumberValueStr());
        orderItem.setSkuCnt(params.getQuantity());

        orderItem.setTotalAmount(orderPrice);
        orderItem.setPaymentAmount(orderPrice);
        orderItem.setTransactionFee(txFee);

        return order;
    }

    @Override
    protected void lockStock(Long sourceId, Integer quantity) {
        // 锁定库存
        marketService.lockStock(sourceId, quantity);
    }

    @Override
    public void orderPayedPost(OrderMain order) {
        // 扣除库存
        OrderItem orderItem = orderItemService.requireOrderItemByOrderMainId(order.getId());
        marketService.takeLockStock(orderItem.getSpuId(), orderItem.getSkuCnt());

        // 分配相关盒子给买家
        // 分为好几种类型：藏品、装备、盒子
        Market marketInfo = marketService.getMarketInfo(orderItem.getSpuId());
        if(marketInfo.getType() == MarketTypeEnum.EQUIPMENT || marketInfo.getType() == MarketTypeEnum.NORMAL){
            // 将用户挂售记录置为已售出
            marketService.soldOut(orderItem.getSpuId());
            userNftService.moveUserNftToUser(orderItem, marketInfo.getSourceId(), order.getSellerUserId(), order.getBuyerUserId(), false);
        }else if(marketInfo.getType() == MarketTypeEnum.BOX){
            userBoxService.moveUserBoxToUser(orderItem, marketInfo.getSourceId(), order.getSellerUserId(), order.getBuyerUserId(), orderItem.getSkuCnt());
            // 如果库存扣光，并且没有锁定库存，直接异步通知将挂单置为已售完状态
            marketService.postNotifySell(orderItem.getSpuId());
        }else if(marketInfo.getType() == MarketTypeEnum.MATERIAL){
            if(Objects.equals(marketInfo.getSourceId(), UserWalletEnum.INTEGRAL.getValue().longValue())){
                // 如果是热豆，则给买家加热豆
                userWalletService.increase(orderItem.getUserId(), UserWalletEnum.INTEGRAL, new BigDecimal(String.valueOf(orderItem.getSkuCnt())), WalletChangeTypeEnum.MARKET_BUY, orderItem.getOrderMainId(), WalletChangeTypeEnum.MARKET_BUY.getMsg());
                marketService.postNotifySell(orderItem.getSpuId());
            }else if(Objects.equals(marketInfo.getSourceId(), UserWalletEnum.WRENCH.getValue().longValue())){
                // 如果是扳手,则给买家加扳手
                userAssetWrenchRecordService.updateWrenchBalance(orderItem.getUserId(), WalletWrenchChangeTypeEnum.WRENCH_MARKET_BUY, WalletChangeDirectionEnum.IN, new BigDecimal(String.valueOf(orderItem.getSkuCnt())),orderItem.getOrderMainId(),"市场购买");
                marketService.postNotifySell(orderItem.getSpuId());
            }else {
                throw new ServiceException("订单类型未处理！");
            }
        }else{
            throw new ServiceException("订单类型未处理！");
        }
        orderService.complete(order.getId(), null);
        // 插入结算队列
        mqSender.send(AppMqNormalEnum.ORDER_SETTLE, order.getId());
    }

    /**
     * 取消订单的执行
     */
    @Override
    public void orderCancelPost(OrderMain orderMain) {
        OrderItem orderItem = orderItemService.requireOrderItemByOrderMainId(orderMain.getId());
        marketService.unlockStock(orderItem.getSpuId(), orderItem.getSkuCnt());
    }
}
